package com.logic.config.web;


import cn.hutool.json.JSONUtil;
import com.logic.comment.util.JwtUtils;
import com.logic.comment.util.RedisUtils;
import com.logic.config.netty.web.model.message.ActionBody;
import com.logic.config.web.messageService.WSChanelService;
import com.logic.config.web.messageService.WSService;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static com.logic.config.web.messageService.WSChanelService.CHANEL_USER_KEY;

@Slf4j
@Component
@ServerEndpoint(value = "/webSocketToUser/{id}", configurator = WebSocketConfig.class)
public class WebSocketToUser {
    private static final String ONLINE_USER_TOKEN_KEY = "onlineUserToken";
    private static ConcurrentHashMap<String, Set<String>> onlineInfo = new ConcurrentHashMap<>();
    @Getter
    public static String sid = "";
    private static ConcurrentHashMap<String, WebSocketToUser> webSocketSet = new ConcurrentHashMap<>();
    // 与某个客户端的连接会话，需要通过它来给客户端发送数据
    private static Session session;
    @Resource
    private RedisUtils redisUtils;


    public static synchronized int getOnlineCount() {
        return onlineInfo.get(ONLINE_USER_TOKEN_KEY).size();
    }

    public static synchronized void addOnlineUserToken(String onlineToken) {
        sid = onlineToken;
        Set<String> strings = onlineInfo.get(ONLINE_USER_TOKEN_KEY);
        if (strings == null || strings.isEmpty()) {
            strings = new HashSet<>();
        }
        if (strings.contains(onlineToken)) {
            return;
        } else {
            strings.add(onlineToken);
            onlineInfo.put(ONLINE_USER_TOKEN_KEY, strings);
        }
        log.info("用戶:{}加入！当前在线人数为：{}", JwtUtils.getPlayerId(sid), getOnlineCount());
    }

    public static synchronized void subOnlineCount() {
        Set<String> strings = onlineInfo.get(ONLINE_USER_TOKEN_KEY);
        strings.remove(sid);
        onlineInfo.put(ONLINE_USER_TOKEN_KEY, strings);
        log.info("用户:{}离开！当前在线人数为：{}", JwtUtils.getPlayerId(sid), getOnlineCount());// 在线数减1
        sid = "";
    }


    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(@PathParam("id") String id, Session session, EndpointConfig config) {
        // 获取WebsocketConfig.java中配置的“sessionId”信息值
        String httpSessionId = (String) config.getUserProperties().get("sessionId");
        WebSocketToUser.session = session;
        WebSocketToUser.sid = id;
        webSocketSet.put(sid, this);     // 加入set中
        addOnlineUserToken(sid);           // 在线数加1
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  // 从set中删除
        subOnlineCount();               // 在线数减1
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        try {
            // 请求处理
            ActionBody actionBody = null;
            try {
                actionBody = JSONUtil.toBean(message, ActionBody.class);
            } catch (Exception e) {
                sendToUser(message, sid);
                log.error("请求参数错误{}", message, e);
                sendToUser("请求参数错误", sid);
                return;
            }
            Integer actionType = actionBody.getActionType();
            Object result = null;
            switch (actionType) {
                case 1:
                    result = WSChanelService.chanelService(actionBody, sid);
                    sendToPanel(sid + ":加入频道:" + result, (Integer) result);
                    break;
                case 2:
                    result = WSService.actionService(actionBody);
                    sendToUser(JSONUtil.toJsonStr(result), sid);
                    break;
                default:
                    sendToUser("请求参数错误", sid);
            }
        } catch (Exception e) {
            log.error("发送消息异常", e);
            sendToUser("发生错误请重试:"+e, sid);
        }
    }

    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) throws IOException {
        error.printStackTrace();
        sendToUser("发生错误请重试", sid);
    }

    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    public boolean sendToUser(String message, String sendUserId) throws IOException {
        if (webSocketSet.get(sendUserId) != null) {
            if (!sid.equals(sendUserId)) {
                return false;
                // webSocketSet.eqlist(sendUserId).sendMessageToUser("用户" + sendUserId + "发来消息：" + message);
            } else {
                webSocketSet.get(sendUserId).sendMessage(message);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return true;
            }
        } else {
            // 如果用户不在线则返回不在线信息给自己  日常
            return false;
        }
    }
    public void sendToPanel(String message, Integer panelNo) throws IOException {
        Map<Object, Object> map = RedisUtils.redisUtils().hGetAll(String.format(CHANEL_USER_KEY, panelNo));
        Set<Object> objects = map.keySet();
        log.info("发送频道消息给:{}", objects);
        for (Object value : map.values()) {
            try {
                sendToUser(message, (String) value);
            } catch (IOException e) {
                log.error("发送频道消息异常", e);
            }
        }
    }
}
